﻿using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Runtime.Versioning;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Log;
using UtilZ.Dotnet.WindowsDesktopEx.Base;
using UtilZ.Dotnet.WindowsDesktopEx.NativeMethod;
using UtilZ.Tool.HostPluginBase;

namespace UtilZ.Tool.WindowsAdapter
{
    /// <summary>
    /// windows系统适配器
    /// </summary>
    [SupportedOSPlatform("windows")]
    public class WindowsAdapter : IOSAdapter
    {
        private readonly static char[] _argsTrimChas = new char[] { '"', '\'', ' ' };

        //private readonly ComputerInfo _computerInfo;
        //private readonly PerformanceCounter _cpuCounter;
        //private readonly OpenHardwareMonitor.Hardware.Computer _computer;
        //private readonly UpdateVisitor _updateVisitor;

        /// <summary>
        /// 构造函数
        /// </summary>
        public WindowsAdapter()
        {

        }




        /// <summary>
        /// 查询进程参数
        /// </summary>
        /// <param name="pid">进程ID</param>
        /// <returns>查询结果</returns>
        public string QueryProcessStartArgs(int pid)
        {
            string commandLine = GetCommandLineArgs(pid);
            return SubArgs(commandLine);
        }

        private static string SubArgs(string commandLine)
        {
            if (string.IsNullOrEmpty(commandLine))
            {
                return null;
            }

            int subIndex = -1;
            bool isFind = false;
            if (commandLine.StartsWith('"'))
            {
                for (int i = 1; i < commandLine.Length; i++)
                {
                    if (isFind)
                    {
                        if (commandLine[i] != ' ')
                        {
                            subIndex = i;
                            break;
                        }
                    }
                    else
                    {
                        if (commandLine[i] == '"')
                        {
                            isFind = true;
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < commandLine.Length; i++)
                {
                    if (isFind)
                    {
                        if (commandLine[i] != ' ')
                        {
                            subIndex = i;
                            break;
                        }
                    }
                    else
                    {
                        if (commandLine[i] == ' ')
                        {
                            isFind = true;
                        }
                    }
                }
            }

            if (subIndex > 0)
            {
                return commandLine.Substring(subIndex).Trim(_argsTrimChas);
            }
            else
            {
                return commandLine.Trim(_argsTrimChas);
            }
        }

        private static string GetCommandLineArgs(int pid)
        {
            try
            {
                using (var searcher = new ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + pid))
                {
                    using (var objects = searcher.Get())
                    {
                        var @object = objects.Cast<ManagementBaseObject>().SingleOrDefault();
                        return @object?["CommandLine"]?.ToString() ?? "";
                    }
                }
            }
            catch (Win32Exception ex) when ((uint)ex.ErrorCode == 0x80004005)
            {
                // 没有对该进程的安全访问权限。
                return string.Empty;
            }
            catch (PlatformNotSupportedException)
            {
                return string.Empty;
            }
            catch (InvalidOperationException)
            {
                // 进程已退出。
                return string.Empty;
            }
        }



        /// <summary>
        /// 获取崩溃进程ID列表
        /// </summary>
        /// <returns></returns>
        public List<int> GetCrushProcessIdList()
        {
            //MainWindow (未响应)
            //return WindowHelper.FindWindows(t => { return t.Title != null && t.Title.EndsWith("(未响应)"); });
            IReadOnlyList<WindowInfo> windowInfoList = WindowHelper.FindWindows();
            if (windowInfoList == null || windowInfoList.Count == 0)
            {
                return null;
            }

            List<int> crushProcessIdList = this.GetCrushProcessIdListByCrushWindowInfo(windowInfoList, null);
            crushProcessIdList = this.GetCsrssCrushProcessIdList(crushProcessIdList);
            crushProcessIdList = this.GetWerfaultCrushProcessIdList(crushProcessIdList);
            crushProcessIdList = this.GetVsjitdebuggerCrushProcessIdList(crushProcessIdList);

            //if (crushProcessIdList == null || crushProcessIdList.Count == 0)
            //{
            //    return windowInfoList.Where(t =>
            //    {
            //        return t.Title != null && t.Title.EndsWith("(未响应)") ||
            //        t.Title.Contains("noResponse", StringComparison.OrdinalIgnoreCase);
            //    }).Select(p => { return p.ProcessId; }).ToList();
            //}

            return crushProcessIdList;
        }

        private List<int> GetCrushProcessIdListByCrushWindowInfo(IReadOnlyList<WindowInfo> windowInfoList, List<int> crushProcessIdList)
        {
            if (windowInfoList == null || windowInfoList.Count == 0)
            {
                return crushProcessIdList;
            }

            var processWindowInfoGroups = windowInfoList.GroupBy(t => { return t.ProcessId; });
            int crushWindowSizeOffset = WindowsAdapterConfig.Instance.CrushWindowSizeOffset;
            List<string> crushWindowTitles = WindowsAdapterConfig.Instance.CrushWindowTitles;
            List<CrushWindowSize> crushWindowSizeList = WindowsAdapterConfig.Instance.CrushWindowSizeList;

            foreach (var processWindowInfoGroup in processWindowInfoGroups)
            {
                try
                {
                    using var proces = Process.GetProcessById(processWindowInfoGroup.Key);

                    WindowInfo crushWindowInfo = null;
                    foreach (var windowInfo in processWindowInfoGroup)
                    {
                        if (windowInfo.Hwnd == proces.MainWindowHandle || windowInfo.ProcessId != proces.Id)
                        {
                            continue;
                        }

                        if (string.Equals(windowInfo.Title, proces.MainWindowTitle))
                        {
                            //标题相同
                            //.net程序崩溃弹窗标题与程序主窗口一致,Bounds{X = 1165 Y = 607 Width = 451 Height = 332(展开)或170(未展开)}	System.Drawing.Rectangle
                            //if ((Math.Abs(windowInfo.Bounds.Width - 451) < crushWindowSizeOffset) && //宽度在451左右
                            //    (Math.Abs(windowInfo.Bounds.Height - 332) < crushWindowSizeOffset || Math.Abs(windowInfo.Bounds.Height - 170) < crushWindowSizeOffset))//高度在332或者170左右
                            //{
                            //    //同时满足以上条件,定义为崩溃弹出的错误提示窗口
                            //    crushWindowInfo = windowInfo;
                            //    break;
                            //}

                            //检查崩溃尺寸
                            if (crushWindowSizeList != null && crushWindowSizeList.Count > 0)
                            {
                                //+		Bounds	{X = 1165 Y = 607 Width = 451 Height = 332}	System.Drawing.Rectangle
                                foreach (var crushWindowSize in crushWindowSizeList)
                                {
                                    if ((Math.Abs(windowInfo.Bounds.Width - crushWindowSize.Width) < crushWindowSizeOffset) &&
                                        (Math.Abs(windowInfo.Bounds.Height - crushWindowSize.Height) < crushWindowSizeOffset))
                                    {
                                        crushWindowInfo = windowInfo;
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                crushWindowInfo = windowInfo;
                                break;
                            }
                        }
                        else
                        {
                            //检查崩溃标题
                            if (crushWindowTitles != null && crushWindowTitles.Count > 0)
                            {
                                //Title = "MainWindow (未响应)"
                                foreach (string crushWindowTitle in crushWindowTitles)
                                {
                                    if (windowInfo.Title.Contains(crushWindowTitle))
                                    {
                                        crushWindowInfo = windowInfo;
                                        break;
                                    }
                                }
                            }

                            //检查崩溃尺寸
                            if (crushWindowInfo == null && crushWindowSizeList != null && crushWindowSizeList.Count > 0)
                            {
                                //+		Bounds	{X = 1165 Y = 607 Width = 451 Height = 332}	System.Drawing.Rectangle
                                foreach (var crushWindowSize in crushWindowSizeList)
                                {
                                    if ((Math.Abs(windowInfo.Bounds.Width - crushWindowSize.Width) < crushWindowSizeOffset) &&
                                        (Math.Abs(windowInfo.Bounds.Height - crushWindowSize.Height) < crushWindowSizeOffset))
                                    {
                                        crushWindowInfo = windowInfo;
                                        break;
                                    }
                                }
                            }

                            if (crushWindowInfo != null)
                            {
                                break;
                            }
                        }
                    }

                    if (crushWindowInfo != null)
                    {
                        //有崩溃窗口弹出来
                        if (crushProcessIdList == null)
                        {
                            crushProcessIdList = new List<int>();
                        }
                        else
                        {
                            if (crushProcessIdList.Contains(proces.Id))
                            {
                                continue;
                            }
                        }

                        crushProcessIdList.Add(proces.Id);

                        //放到需要的地方去干掉进程,此处不作相关操作,毕竟不合理
                        // WindowHelper.SendMessage(crushWindowInfo.Hwnd, WindowMessages.WM_NEXTDLGCTL, 0, 0);//无效
                        // WindowHelper.SendMessage(crushWindowInfo.Hwnd, WindowMessages.WM_CLOSE, 0, 0);//关闭崩溃窗口继续
                        //process.Kill();//杀死崩溃进程
                    }
                }
                catch (Exception ex)
                {
                    Loger.Warn(ex, "根据进程ID判决崩溃进程异常,忽略...");
                }
            }

            return crushProcessIdList;
        }

        private List<int> GetCsrssCrushProcessIdList(List<int> crushProcessIdList)
        {
            //List<int> crushProcessIdList = null;
            Process[] csrssProcessArr = Process.GetProcessesByName("csrss");//csrss.exe进程
            int colonIndex, minusIndex;
            string errProcessName;
            foreach (var csrssProcess in csrssProcessArr)
            {
                try
                {
                    if (string.IsNullOrWhiteSpace(csrssProcess.MainWindowTitle))
                    {
                        continue;
                    }

                    //csrssProcess.MainWindowTitle：excepiton_console.exe - 应用程序错误
                    //csrssProcess.MainWindowTitle：MainWindow: exception_qt.exe - 应用程序错误

                    minusIndex = csrssProcess.MainWindowTitle.LastIndexOf('-');
                    if (minusIndex < 0)
                    {
                        continue;
                    }

                    colonIndex = csrssProcess.MainWindowTitle.IndexOf(':');
                    if (colonIndex > 0)
                    {
                        errProcessName = Path.GetFileNameWithoutExtension(csrssProcess.MainWindowTitle.Substring(colonIndex + 1, minusIndex - colonIndex).Trim());
                    }
                    else
                    {
                        errProcessName = Path.GetFileNameWithoutExtension(csrssProcess.MainWindowTitle.Substring(0, minusIndex).Trim());
                    }

                    var crushOriginProcessArr = Process.GetProcessesByName(errProcessName);
                    if (crushOriginProcessArr.Length > 0)
                    {
                        //if (crushProcessIdList == null)
                        //{
                        //    crushProcessIdList = new List<int>();
                        //}

                        foreach (var crushOriginProcesse in crushOriginProcessArr)
                        {
                            crushOriginProcesse.Dispose();
                        }

                        csrssProcess.CloseMainWindow();//只需要关掉此窗口,该进程就自动结束,然后看门狗就自动重启
                    }
                }
                catch (Exception ex)
                {
                    Loger.Warn(ex);
                }

                csrssProcess.Dispose();
            }

            return crushProcessIdList;
        }

        private List<int> GetVsjitdebuggerCrushProcessIdList(List<int> crushProcessIdList)
        {
            Process[] vsjitdebuggerProcessArr = Process.GetProcessesByName("vsjitdebugger");//vsjitdebugger.exe进程
            foreach (var vsjitdebuggerProcess in vsjitdebuggerProcessArr)
            {
                if (string.IsNullOrWhiteSpace(vsjitdebuggerProcess.MainWindowTitle))
                {
                    continue;
                }

                vsjitdebuggerProcess.CloseMainWindow();//只需要关掉此窗口,该进程就自动结束,然后看门狗就自动重启
                vsjitdebuggerProcess.Dispose();
            }

            return crushProcessIdList;
        }

        //仅支持windows桌面程序,控制台不支持,只能舍弃了
        private List<int> GetWerfaultCrushProcessIdList(List<int> crushProcessIdList)
        {
            //List<int> crushProcessIdList = null;
            Process[] werfaultProcessArr = Process.GetProcessesByName("werfault");//Werfault.exe进程
            foreach (var werfaultProcess in werfaultProcessArr)
            {
                try
                {
                    var werfaultCheckProcessId = this.GetWerfaultProcessId(werfaultProcess.Id);
                    werfaultProcess.Kill();
                    werfaultProcess.Dispose();
                    if (werfaultCheckProcessId <= 0 ||
                        crushProcessIdList != null && crushProcessIdList.Contains(werfaultCheckProcessId))
                    {
                        continue;
                    }

                    if (crushProcessIdList == null)
                    {
                        crushProcessIdList = new List<int>();
                    }
                    crushProcessIdList.Add(werfaultCheckProcessId);
                }
                catch (Exception ex)
                {
                    Loger.Warn(ex);
                }

                werfaultProcess.Dispose();
            }

            return crushProcessIdList;
        }

        /// <summary>
        /// 获取进程命令行信息
        /// </summary>
        /// <param name="pId"></param>
        /// <returns></returns>
        private int GetWerfaultProcessId(int werfaultProcessId)
        {
            try
            {
                using (ManagementObjectSearcher search = new ManagementObjectSearcher($"select CommandLine from Win32_Process where ProcessId={werfaultProcessId}"))
                {
                    using (ManagementObjectCollection moc = search.Get())
                    {
                        object obj;
                        foreach (ManagementObject mo in moc)
                        {
                            //werfault.exe /h /shared Global\\409752f6ec4c49a7a9aaaf24be671079 /t 10084 /p 29732
                            obj = mo["CommandLine"];
                            if (obj == null)
                            {
                                continue;
                            }

                            string commandLine = obj.ToString();
                            if (string.IsNullOrWhiteSpace(commandLine))
                            {
                                continue;
                            }

                            const string PRO_PARA = "/p";
                            int index = commandLine.IndexOf(PRO_PARA);
                            if (index >= 0)
                            {
                                string pidStr = commandLine.Substring(index + PRO_PARA.Length).Trim();
                                index = pidStr.IndexOf(' ');
                                if (index > 0)
                                {
                                    pidStr = pidStr.Substring(0, index).Trim();
                                }

                                int pid;
                                if (int.TryParse(pidStr, out pid))
                                {
                                    return pid;
                                }
                            }
                            break;
                        }
                    }
                }
            }
            catch (ManagementException)
            { }
            catch (System.Runtime.InteropServices.COMException)
            { }

            return -1;
        }




        public bool IsNoResponse(IntPtr mainWindowHandle)
        {
            return WindowHelper.IsNoResponse(mainWindowHandle);
        }




        public float GetCpuUsageRate()
        {
            /********************************************************************************
             * 
             * Microsoft Windows [版本 10.0.19044.1288]
             * (c) Microsoft Corporation。保留所有权利。
             * 
             * D:\SelfCode\UtilZ\UtilZ.Tool.Host\App\UtilZ.Tool.HostAgent\bin\Debug\net7.0>typeperf "processor(_total)\% processor time" -sc 1
             * 
             * "(PDH-CSV 4.0)","\\DESKTOP-AC6C0JC\processor(_total)\% processor time"
             * "04/18/2023 15:12:53.189","5.148593"
             * 正在退出，请稍候...                        
             * 命令成功结束。
             * 
             * 
             * 
             * D:\SelfCode\UtilZ\UtilZ.Tool.Host\App\UtilZ.Tool.HostAgent\bin\Debug\net7.0>
            ********************************************************************************/
            string text = ProcessEx.ExecuteCommand(@"typeperf ""processor(_total)\% processor time"" -sc 1");
            //string regexStr = @"\d[1-2]:\d[1-2]:\d[1-2]\.\d+";


            int index = text.LastIndexOf(',');
            if (index > 0)
            {
                string usageStr = text.Substring(index).Trim('"');
                float.TryParse(usageStr, out float value);
                {
                    return value;
                }
            }

            return 0f;
        }
    }
}